/**
 * 
 */
package view.impl;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import model.EMenuState;
import model.ModelFactory;
import model.impl.menu.IMainMenu;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;

import util.CharacterLoadException;
import util.CharacterLoader;
import util.ResLoc;
import view.impl.menu.SingleLayeredMenu;
import view.impl.menu.items.CharSelectObject;
import view.impl.menu.items.MenuButton;


/**
 * A class that implements the interface IViewState. Defines a state that displays
 * the character selection screen where the player can choose what character to
 * play with.
 * 
 * @author Julian Lindblad
 *
 */
public class CharSelectState implements IViewState {

	//private static CharSelectState INSTANCE = new CharSelectState();
	private static final int NUMBER_BUTTONS  = 2;
	
	private Image background;
	private List<CharSelectObject> characters = new LinkedList<CharSelectObject>();
	
	private SingleLayeredMenu menu = new SingleLayeredMenu();
	
	private int windowWidth = 800;
	private int windowHeight = 600;
	
//	/**
//	 * @return A singleton instance of CharSelectState.
//	 */
//	public static CharSelectState getInstance() {
//		return INSTANCE;
//	}
	
	/**
	 * Private constructor, as defined in Singleton-pattern.
	 */
	CharSelectState() throws RenderException {
		init();
	}
	
	/**
	 * Initiates the character selection screen.
	 */
	private void init() throws RenderException{
		float scaleX = (float)windowWidth / 800f;
		float scaleY = (float)windowHeight / 600f;
		
		try {
			background = new Image(ResLoc.getResource("CharSelect.background"));
		} catch (SlickException e) {
			throw new RenderException("Unable to draw background in character selection screen.", e);
		} catch (FileNotFoundException e) {
			throw new RenderException("Unable to draw background in character selection screen.", e);
		}
		
		initButtons(scaleX, scaleY);
		
		initCharacters(scaleX, scaleY);
	}

	/**
	 * Initiates the button used in this state.
	 * 
	 * @param scaleX How much the resolution is scaled on the width.
	 * @param scaleY How much the resolution is scaled on the height.
	 * @throws RenderException 
	 */
	private void initButtons(float scaleX, float scaleY) throws RenderException {
		// Add buttons.
		UnicodeFont uFont;
		try {
			uFont = FontContainer.getMenuFont();
		} catch (SlickException e) {
			throw new RenderException("Unable to load font in character selection screen.", e);
		} catch (FileNotFoundException e) {
			throw new RenderException("Unable to load font in character selection screen.", e);
		}
		
		MenuButton backButton = new MenuButton("Back", 
											   uFont, 
											   (int)(50 * scaleX), 
											   (int)(550 * scaleY - uFont.getHeight("Back") / 2f));
		
		MenuButton playButton = new MenuButton("Play", 
											   uFont, 
											   (int) (750 * scaleX - uFont.getWidth("Play")), 
											   (int)(550 * scaleY - uFont.getHeight("Play") / 2f));
		
		menu.addMenuItem(backButton, 0);
		menu.addMenuItem(playButton, 1);
	}

	/**
	 * Initiates the images on each character.
	 * 
	 * @param scaleX How much the resolution is scaled on the width.
	 * @param scaleY How much the resolution is scaled on the height.
	 */
	private void initCharacters(float scaleX, float scaleY) throws RenderException {
		// Add characters.
		float scale = (scaleX + scaleY) / 2;
		
		Map<Integer, CharacterInfo> charactersMap;
		try {
			charactersMap = CharacterLoader.getCharacterMap();
		} catch (CharacterLoadException e) {
			throw new RenderException("Unable to load characters in character selection screen.", e);
		}
		List<Integer> keys = new ArrayList<Integer>(charactersMap.keySet());
		Collections.sort(keys);
		
		int titleMarg = 100;
		int nbChars = keys.size();
		int gridSize = 200 ;
		int margSize = 20;
		int imageSize = (int) (160 * scale);
		for(int i = 0; i < nbChars; i++) {
			// Place the characters in a 2 * 8-grid.
			int gridPosX = i % 4;
			int gridPosY = i / 4;
			
			int posX = (int) ((gridPosX * gridSize + margSize) * scaleX);
			int posY = (int) ((gridPosY * gridSize + margSize + titleMarg) * scaleY);
			
			try {
				CharSelectObject co = new CharSelectObject(charactersMap.get(keys.get(i)), 
														   posX, 
														   posY, 
														   (int)(imageSize * scale));
				menu.addMenuItem(co, i + NUMBER_BUTTONS);
				characters.add(co);
				
			} catch (SlickException e) {
				throw new RenderException("Unable to create character selection for character screen.", e);
			}
		}
	}
	
	/* (non-Javadoc)
	 * @see client.view.IViewState#changeResolution(int, int)
	 */
	@Override
	public void changeResolution(int targetWidth, int targetHeight) {
		windowWidth = targetWidth;
		windowHeight = targetHeight;
	}

	/* (non-Javadoc)
	 * @see client.view.IViewState#render(client.view.RenderParameters)
	 */
	@Override
	public void render(Graphics g) {
		background.draw(0, 0, windowWidth, windowHeight);
		
		IMainMenu model = ModelFactory.getViewModel().getMenuState();
		
		if(model.getChosenCharacterIndex() > 1) {
			for(int i = 0; i < characters.size(); i++) {
				characters.get(i).setChosen(i == model.getChosenCharacterIndex() - NUMBER_BUTTONS);
			}
		}
		
		menu.draw(model.getMarkedAlternative(), g, windowWidth, windowHeight);
	}

	@Override
	public EMenuState getEMenuTyoe() {
		return EMenuState.CHARACTER_SELECTION;
	}
}
